/////////////
#ifndef GITEE_STRING_VIEW_HPP
#define GITEE_STRING_VIEW_HPP
#include "depends/string_view.hpp"
#include <cstring>
#include <string>

namespace gitee {
using nonstd::string_view;

// StrContains()
//
// Returns whether a given string `haystack` contains the substring `needle`.
inline bool StrContains(gitee::string_view haystack,
                        gitee::string_view needle) {
  return haystack.find(needle, 0) != gitee::string_view::npos;
}

// StartsWith()
//
// Returns whether a given string `text` begins with `prefix`.
inline bool StartsWith(gitee::string_view text, gitee::string_view prefix) {
  return prefix.empty() ||
         (text.size() >= prefix.size() &&
          memcmp(text.data(), prefix.data(), prefix.size()) == 0);
}

// EndsWith()
//
// Returns whether a given string `text` ends with `suffix`.
inline bool EndsWith(gitee::string_view text, gitee::string_view suffix) {
  return suffix.empty() || (text.size() >= suffix.size() &&
                            memcmp(text.data() + (text.size() - suffix.size()),
                                   suffix.data(), suffix.size()) == 0);
}

// ConsumePrefix()
//
// Strips the `expected` prefix from the start of the given string, returning
// `true` if the strip operation succeeded or false otherwise.
//
// Example:
//
//   gitee::string_view input("abc");
//   EXPECT_TRUE(absl::ConsumePrefix(&input, "a"));
//   EXPECT_EQ(input, "bc");
inline bool ConsumePrefix(gitee::string_view *str,
                          gitee::string_view expected) {
  if (!gitee::StartsWith(*str, expected)) {
    return false;
  }
  str->remove_prefix(expected.size());
  return true;
}
// ConsumeSuffix()
//
// Strips the `expected` suffix from the end of the given string, returning
// `true` if the strip operation succeeded or false otherwise.
//
// Example:
//
//   gitee::string_view input("abcdef");
//   EXPECT_TRUE(absl::ConsumeSuffix(&input, "def"));
//   EXPECT_EQ(input, "abc");
inline bool ConsumeSuffix(gitee::string_view *str,
                          gitee::string_view expected) {
  if (!gitee::EndsWith(*str, expected)) {
    return false;
  }
  str->remove_suffix(expected.size());
  return true;
}

// StripPrefix()
//
// Returns a view into the input string 'str' with the given 'prefix' removed,
// but leaving the original string intact. If the prefix does not match at the
// start of the string, returns the original string instead.
inline gitee::string_view StripPrefix(gitee::string_view str,
                                      gitee::string_view prefix) {
  if (gitee::StartsWith(str, prefix)) {
    str.remove_prefix(prefix.size());
  }
  return str;
}

// StripSuffix()
//
// Returns a view into the input string 'str' with the given 'suffix' removed,
// but leaving the original string intact. If the suffix does not match at the
// end of the string, returns the original string instead.
inline gitee::string_view StripSuffix(gitee::string_view str,
                                      gitee::string_view suffix) {
  if (gitee::EndsWith(str, suffix)) {
    str.remove_suffix(suffix.size());
  }
  return str;
}

namespace gitee_internal {
inline std::string CatPieces(std::initializer_list<gitee::string_view> pieces) {
  std::string result;
  size_t total_size = 0;
  for (const gitee::string_view piece : pieces) {
    total_size += piece.size();
  }
  result.reserve(total_size);

  for (const gitee::string_view piece : pieces) {
    result.append(piece.data(), piece.size());
  }
  return result;
}
} // namespace gitee_internal

inline std::string StrCat(gitee::string_view s0, gitee::string_view s1) {
  std::string s;
  s.reserve(s0.size() + s1.size());
  s.assign(s0.data(), s0.size()).append(s1.data(), s1.size());
  return s;
}

inline std::string StrCat(gitee::string_view s0, gitee::string_view s1,
                          gitee::string_view s2) {
  std::string s;
  s.reserve(s0.size() + s1.size() + s2.size());
  s.assign(s0.data(), s0.size())
      .append(s1.data(), s1.size())
      .append(s2.data(), s2.size());
  return s;
}

inline std::string StrCat(gitee::string_view s0, gitee::string_view s1,
                          gitee::string_view s2, gitee::string_view s3) {
  std::string s;
  s.reserve(s0.size() + s1.size() + s2.size() + s3.size());
  s.assign(s0.data(), s0.size())
      .append(s1.data(), s1.size())
      .append(s2.data(), s2.size())
      .append(s3.data(), s3.size());
  return s;
}

inline std::string StrCat(gitee::string_view s0, gitee::string_view s1,
                          gitee::string_view s2, gitee::string_view s3,
                          gitee::string_view s4) {
  std::string s;
  s.reserve(s0.size() + s1.size() + s2.size() + s3.size() + s4.size());
  s.assign(s0.data(), s0.size())
      .append(s1.data(), s1.size())
      .append(s2.data(), s2.size())
      .append(s3.data(), s3.size())
      .append(s4.data(), s4.size());
  return s;
}

template <typename... AV>
inline std::string StrCat(gitee::string_view a, gitee::string_view b,
                          gitee::string_view c, gitee::string_view d,
                          gitee::string_view e, AV... args) {
  return gitee::gitee_internal::CatPieces({a, b, c, d, e, args...});
}

} // namespace gitee

#endif
